
package com.jf.cloud.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.i18n.LanguageEnum;
import com.jf.cloud.common.product.constant.TakeStockBillStatus;
import com.jf.cloud.common.product.constant.TakeStockSpuStatus;
import com.jf.cloud.common.product.dto.SpuDTO;
import com.jf.cloud.common.product.vo.SkuVO;
import com.jf.cloud.common.product.vo.SpuVO;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.ExcelUtil;
import com.jf.cloud.product.dto.TakeStockDTO;
import com.jf.cloud.product.mapper.SpuMapper;
import com.jf.cloud.product.mapper.TakeStockMapper;
import com.jf.cloud.product.mapper.TakeStockSpuMapper;
import com.jf.cloud.product.model.Sku;
import com.jf.cloud.product.model.TakeStock;
import com.jf.cloud.product.model.TakeStockSpu;
import com.jf.cloud.product.service.SpuService;
import com.jf.cloud.product.service.TakeStockSpuService;
import com.jf.cloud.product.vo.TakeStockExcelVO;
import com.jf.cloud.product.vo.TakeStockSpuExcelVO;
import com.jf.cloud.product.vo.TakeStockSpuImportVO;
import com.jf.cloud.product.vo.TakeStockSpuVO;
import org.apache.commons.math3.stat.descriptive.summary.Product;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 盘点商品列表
 *
 * @author zz
 * @date 2022-06-22 16:57:27
 */
@Service
public class TakeStockSpuServiceImpl implements TakeStockSpuService {

    @Autowired
    private TakeStockSpuMapper takeStockSpuMapper;
    @Autowired
    private TakeStockMapper takeStockMapper;
    @Autowired
    private SpuMapper spuMapper;

    @Override
    public PageVO<TakeStockSpu> page(PageDTO pageDTO) {
        return PageUtil.doPage(pageDTO, () -> takeStockSpuMapper.list());
    }

    @Override
    public TakeStockSpu getByTakeStockSpuId(Long takeStockSpuId) {
        return takeStockSpuMapper.getByTakeStockSpuId(takeStockSpuId);
    }

    @Override
    public void save(TakeStockSpu takeStockSpu) {
        takeStockSpuMapper.save(takeStockSpu);
    }

    @Override
    public void update(TakeStockSpu takeStockSpu) {
        takeStockSpuMapper.update(takeStockSpu);
    }

    @Override
    public void deleteById(Long takeStockSpuId) {
        takeStockSpuMapper.deleteById(takeStockSpuId);
    }

    @Override
    public void updateByTakeStockDTO(TakeStockDTO takeStockDTO) {
        // 先删后增
        Long takeStockId = takeStockDTO.getTakeStockId();
        takeStockSpuMapper.deleteByTackStockId(takeStockId);
        if (CollectionUtils.isEmpty(takeStockDTO.getTakeStockSpuList())) {
            return;
        }
        takeStockSpuMapper.saveBatch(takeStockDTO.getTakeStockSpuList());
    }

    @Override
    public List<TakeStockSpuVO> listByTakeStockId(Long takeStockId) {
        List<TakeStockSpuVO> takeStockSpuList = takeStockSpuMapper.listByTakeStockId(takeStockId, I18nMessage.getLang());
        return takeStockSpuList;
    }

    @Override
    public void downloadModel(HttpServletResponse response) {
        ExcelWriter excelWriter = null;
        try {
            excelWriter = ExcelUtil.getExcelWriterMerge(
                    response,
                    TakeStockSpuExcelVO.EXCEL_NAME,
                    TakeStockSpuExcelVO.MERGE_ROW_INDEX,
                    TakeStockSpuExcelVO.MERGE_COLUMN_INDEX
            ).build();
            // 进行写入操作
            WriteSheet sheetWriter = EasyExcel
                    .writerSheet(TakeStockSpuExcelVO.SHEET_NAME)
                    .head(TakeStockSpuExcelVO.class)
                    .build();
            excelWriter.write(Collections.emptyList(), sheetWriter);
        } catch (Exception e) {
            System.out.println("导出实物盘点导入模板excel失败，原因：" + e.getMessage());
        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    @Override
    public void importExcel(List<TakeStockSpuExcelVO> list, List<String> errorList, Long takeStockId, TakeStockSpuImportVO takeStockSpuImportVO) {
        if (CollectionUtils.isEmpty(list)) {
            takeStockSpuImportVO.setTips("导入数据为空，请检查下文件");
            return;
        }
        TakeStock takeStock = takeStockMapper.getByTakeStockId(takeStockId);
        if (takeStock == null) {
            takeStockSpuImportVO.setTips("实物盘点不存在");
            return;
        }
        if (Objects.equals(takeStock.getBillStatus(), TakeStockBillStatus.VOIDED.value()) ||
                Objects.equals(takeStock.getBillStatus(), TakeStockBillStatus.COMPLETED.value())) {
            takeStockSpuImportVO.setTips("当前盘点任务已完成或已作废，请返回列表页面后刷新");
            return;
        }
        List<TakeStockSpuVO> takeStockSpuVOList = this.listByTakeStockId(takeStockId);
        if (CollectionUtil.isNotEmpty(takeStockSpuVOList)) {
            takeStockSpuImportVO.setTips("该盘点单已有商品导入，无法使用批量导入功能");
        }
        // 获取商品对应sku及库存
        SpuDTO spuDTO = new SpuDTO();
        spuDTO.setShopId(AuthUserContext.get().getTenantId());
        spuDTO.setStatus(1);
        List<SpuVO> spuVOList = spuMapper.pageSpuSku(spuDTO, null);
        if (CollectionUtils.isEmpty(spuVOList)) {
            takeStockSpuImportVO.setTips("店铺不存在状态正常的商品");
            return;
        }
        List<SkuVO> skuVOList = new ArrayList<>();
        for (SpuVO spuVO : spuVOList) {
            skuVOList.addAll(spuVO.getSkus());
        }
        Map<String, List<SkuVO>> partyCodeSkusMap = skuVOList.stream().collect(Collectors.groupingBy(SkuVO::getPartyCode));
        // 校验excel数据，新增excel数据
        int i = 3;
        List<SkuVO> skuTempList;
        SkuVO skuVO;
        List<TakeStockSpu> takeStockSpuList = new ArrayList<>(16);
        TakeStockSpu takeStockSpu;
        Integer ioType;
        for (TakeStockSpuExcelVO excel : list) {
            try{
                // 必填校验
                if (excel.getPartyCode() == null) {
                    throw new LuckException("商品编码不能为空");
                }
                // 合法性校验
                skuTempList = partyCodeSkusMap.get(excel.getPartyCode());
                if (skuTempList == null) {
                    throw new LuckException("商品编码不存在");
                }
                if (skuTempList.size() > 1) {
                    throw new LuckException("该商品编码下存在多个商品规格");
                }
                if (excel.getChangeStock() == null) {
                   excel.setChangeStock(0);
                }
                // 构建takeStockSpu
                skuVO = skuTempList.get(0);
                takeStockSpu = new TakeStockSpu();
                takeStockSpu.setTakeStockId(takeStockId);
                takeStockSpu.setSpuId(skuVO.getSpuId());
                takeStockSpu.setSkuId(skuVO.getSkuId());
                takeStockSpu.setStocks(skuVO.getStock());
                takeStockSpu.setTotalStock(excel.getChangeStock());
                if (skuVO.getStock().compareTo(excel.getChangeStock()) == 0) {
                    ioType = TakeStockSpuStatus.EQUAL.value();
                } else if (skuVO.getStock().compareTo(excel.getChangeStock()) > 0) {
                    ioType = TakeStockSpuStatus.PROFIT.value();
                } else {
                    ioType = TakeStockSpuStatus.LOSS.value();
                }
                takeStockSpu.setIoType(ioType);
                takeStockSpuList.add(takeStockSpu);
            } catch (Exception e) {
                errorList.add("第" + i + "行数据有错误：" + e.getMessage());
            }
        }
        // 数据插入
        if (takeStockSpuList.size() > 0) {
            takeStockSpuMapper.saveBatch(takeStockSpuList);
        }
        String tips = "检查到" + list.size() + "条商品信息，成功导入" +
                (takeStockSpuList.size()) + "条商品信息！错误" + (list.size() - takeStockSpuList.size()) + "条商品信息!" +
                (CollUtil.isNotEmpty(errorList) ? errorList.toString() : "");
        takeStockSpuImportVO.setTips(tips);
        takeStockSpuImportVO.setTakeStockSpuList(takeStockSpuList);
    }

    @Override
    public void exportExcel(Long takeStockId, HttpServletResponse response) {
        // 获取excel导出数据
        TakeStockDTO takeStockDTO = new TakeStockDTO();
        takeStockDTO.setTakeStockId(takeStockId);
        takeStockDTO.setShopId(AuthUserContext.get().getTenantId());
        List<TakeStockExcelVO> takeStockExcelVOList = takeStockMapper.listTakeStockExportData(takeStockDTO, I18nMessage.getLang());
        // 字典数据信息补充
        TakeStockBillStatus billStatusEnum;
        TakeStockSpuStatus spuStatusEnum;
        for (TakeStockExcelVO takeStockExcelVO : takeStockExcelVOList) {
            billStatusEnum = TakeStockBillStatus.instance(takeStockExcelVO.getBillStatus());
            takeStockExcelVO.setBillStatusStr(billStatusEnum == null ? "" : billStatusEnum.strCn());
            spuStatusEnum = TakeStockSpuStatus.instance(takeStockExcelVO.getIoType());
            takeStockExcelVO.setIoTypeStr(spuStatusEnum == null ? "" : spuStatusEnum.str());
        }
        // 数据导出为excel
        ExcelWriter excelWriter = null;
        try {
            // 先执行合并策略
            excelWriter = ExcelUtil.getExcelWriterMerge(response, TakeStockExcelVO.EXCEL_NAME, TakeStockExcelVO.MERGE_ROW_INDEX, TakeStockExcelVO.MERGE_COLUMN_INDEX).build();
            if (CollUtil.isNotEmpty(takeStockExcelVOList)){
                // 进行写入操作
                WriteSheet sheetWriter = EasyExcel
                        .writerSheet(TakeStockExcelVO.SHEET_NAME)
                        .head(TakeStockExcelVO.class)
                        .build();
                excelWriter.write(takeStockExcelVOList, sheetWriter);
            }
        } catch (Exception e) {
            System.out.println("导出excel失败: " + e.getMessage());
        }finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}
